﻿using System;
using System.Numerics;

namespace UtilZ.Dotnet.Ex.Base
{
    /// <summary>
    ///  Type类型扩展方法类
    /// </summary>
    public static partial class TypeEx
    {
        /// <summary>
        /// 判断原生数据类型是否为值类型
        /// </summary>
        /// <param name="primitiveDataType">原生数据类型</param>
        /// <returns>对象的基元类型</returns>
        public static bool IsValueType(PrimitiveDataTypes primitiveDataType)
        {
            switch (primitiveDataType)
            {
                case PrimitiveDataTypes.Bool:
                case PrimitiveDataTypes.Char:
                case PrimitiveDataTypes.SByte:
                case PrimitiveDataTypes.Byte:
                case PrimitiveDataTypes.Int16:
                case PrimitiveDataTypes.UInt16:
                case PrimitiveDataTypes.Int32:
                case PrimitiveDataTypes.UInt32:
                case PrimitiveDataTypes.Int64:
                case PrimitiveDataTypes.UInt64:
#if CORE
                case PrimitiveDataTypes.Int128:
                case PrimitiveDataTypes.UInt128:
#endif
                case PrimitiveDataTypes.BigInteger:

                case PrimitiveDataTypes.Half:
                case PrimitiveDataTypes.Float:
                case PrimitiveDataTypes.Double:
                case PrimitiveDataTypes.Decimal:

                case PrimitiveDataTypes.Enum:
                case PrimitiveDataTypes.DateTime:
                case PrimitiveDataTypes.TimeSpan:
                case PrimitiveDataTypes.DateTimeOffset:
                case PrimitiveDataTypes.TimeOnly:
                case PrimitiveDataTypes.DateOnly:
                    return true;
                default:
                    return false;
            }
        }


        /// <summary>
        /// 获取对象的基元类型
        /// </summary>
        /// <param name="obj">对象</param>
        /// <returns>对象的基元类型</returns>
        public static PrimitiveDataTypes GetPrimitiveDataType(object obj)
        {
            if (obj == null)
            {
                return PrimitiveDataTypes.Class;
            }

            if (obj is bool)
            {
                return PrimitiveDataTypes.Bool;
            }

            if (obj is char)
            {
                return PrimitiveDataTypes.Char;
            }

            if (obj is byte)
            {
                return PrimitiveDataTypes.Byte;
            }

            if (obj is sbyte)
            {
                return PrimitiveDataTypes.SByte;
            }

            if (obj is Int16)
            {
                return PrimitiveDataTypes.Int16;
            }

            if (obj is UInt16)
            {
                return PrimitiveDataTypes.UInt16;
            }

            if (obj is Int32)
            {
                return PrimitiveDataTypes.Int32;
            }

            if (obj is UInt32)
            {
                return PrimitiveDataTypes.UInt32;
            }

            if (obj is Int64)
            {
                return PrimitiveDataTypes.Int64;
            }

            if (obj is UInt64)
            {
                return PrimitiveDataTypes.UInt64;
            }

#if CORE7_P

            if (obj is Int128)
            {
                return PrimitiveDataTypes.Int128;
            }

            if (obj is UInt128)
            {
                return PrimitiveDataTypes.UInt128;
            }
#endif

#if CORE
            if (obj is Half)
            {
                return PrimitiveDataTypes.Half;
            }

            if (obj is TimeOnly)
            {
                return PrimitiveDataTypes.TimeOnly;
            }

            if (obj is DateOnly)
            {
                return PrimitiveDataTypes.DateOnly;
            }
#endif

            if (obj is BigInteger)
            {
                return PrimitiveDataTypes.BigInteger;
            }

            if (obj is float)
            {
                return PrimitiveDataTypes.Float;
            }

            if (obj is double)
            {
                return PrimitiveDataTypes.Double;
            }

            if (obj is decimal)
            {
                return PrimitiveDataTypes.Decimal;
            }

            if (obj is DateTime)
            {
                return PrimitiveDataTypes.DateTime;
            }

            if (obj is TimeSpan)
            {
                return PrimitiveDataTypes.TimeSpan;
            }

            if (obj is DateTimeOffset)
            {
                return PrimitiveDataTypes.DateTimeOffset;
            }

            if (obj is Enum)
            {
                return PrimitiveDataTypes.Enum;
            }
            
            if (obj is string)
            {
                return PrimitiveDataTypes.String;
            }

            if (obj is byte[])
            {
                return PrimitiveDataTypes.ByteAarray;
            }

            if (obj is short[])
            {
                return PrimitiveDataTypes.Int16Aarray;
            }

            if (obj is float[])
            {
                return PrimitiveDataTypes.FloatAarray;
            }

            if (obj is int[])
            {
                return PrimitiveDataTypes.Int32Aarray;
            }

            if (obj is double[])
            {
                return PrimitiveDataTypes.DoubleAarray;
            }

            return PrimitiveDataTypes.None;
        }
        
        /// <summary>
        /// 获取对象的基元类型
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <returns>对象的基元类型</returns>
        public static PrimitiveDataTypes GetPrimitiveDataType<T>()
        {
            return ConvertPrimitiveDataType(typeof(T));
        }

        /// <summary>
        /// 获取对象的基元类型
        /// </summary>
        /// <param name="type">类型</param>
        /// <returns>对象的基元类型</returns>
        public static PrimitiveDataTypes ConvertPrimitiveDataType(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }

            if (type.IsEnum)
            {
                return PrimitiveDataTypes.Enum;
            }

            switch (Type.GetTypeCode(type))
            {
                case TypeCode.Boolean:
                    return PrimitiveDataTypes.Bool;
                case TypeCode.Char:
                    return PrimitiveDataTypes.Char;
                case TypeCode.Byte:
                    return PrimitiveDataTypes.Byte;
                case TypeCode.SByte:
                    return PrimitiveDataTypes.SByte;
                case TypeCode.Int16:
                    return PrimitiveDataTypes.Int16;
                case TypeCode.UInt16:
                    return PrimitiveDataTypes.UInt16;

                case TypeCode.Int32:
                    return PrimitiveDataTypes.Int32;
                case TypeCode.UInt32:
                    return PrimitiveDataTypes.UInt32;
                case TypeCode.Int64:
                    return PrimitiveDataTypes.Int64;
                case TypeCode.UInt64:
                    return PrimitiveDataTypes.UInt64;
                case TypeCode.Single:
                    return PrimitiveDataTypes.Float;

                case TypeCode.Double:
                    return PrimitiveDataTypes.Double;
                case TypeCode.Decimal:
                    return PrimitiveDataTypes.Decimal;
                case TypeCode.String:
                    return PrimitiveDataTypes.String;
                case TypeCode.DateTime:
                    return PrimitiveDataTypes.DateTime;
                default:

#if CORE7_P
                    if (type == Int128Type)
                    {
                        return PrimitiveDataTypes.Int128;
                    }

                    if (type == UInt128Type)
                    {
                        return PrimitiveDataTypes.UInt128;
                    }
#endif


#if CORE
                    if (type == BigIntegerType)
                    {
                        return PrimitiveDataTypes.BigInteger;
                    }

                    if (type == HalfType)
                    {
                        return PrimitiveDataTypes.Half;
                    }

                    if (type == TimeOnlyType)
                    {
                        return PrimitiveDataTypes.TimeOnly;
                    }

                    if (type == DateOnlyType)
                    {
                        return PrimitiveDataTypes.DateOnly;
                    }
#endif
                    if (type == TimeSpanType)
                    {
                        return PrimitiveDataTypes.TimeSpan;
                    }

                    if (type == DateTimeOffsetType)
                    {
                        return PrimitiveDataTypes.DateTimeOffset;
                    }

                    if (type == ByteAarrayType)
                    {
                        return PrimitiveDataTypes.ByteAarray;
                    }

                    if (type == ShortAarrayType)
                    {
                        return PrimitiveDataTypes.Int16Aarray;
                    }

                    if (type == Int32AarrayType)
                    {
                        return PrimitiveDataTypes.Int32Aarray;
                    }

                    if (type == DoubleAarrayType)
                    {
                        return PrimitiveDataTypes.DoubleAarray;
                    }

                    //if (type.IsValueType)
                    //{
                    //    return PrimitiveDataTypes.ValueType;
                    //}

                    //if (type.IsClass)
                    //{
                    //    return PrimitiveDataTypes.ReferenceType;
                    //}
                    break;
            }

            return PrimitiveDataTypes.None;
        }

    }

}
